#include <stdio.h>
#include <stddef.h>

#include "oled.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_i2c.h"
#include "iot_errno.h"
#include "oled_fonts.h"

#define OLED_I2C_IDX 0
#define OLED_I2C_ADDR 0x78           // 默认地址为 0x78
#define OLED_I2C_CMD 0x00            // 0000 0000       写命令
#define OLED_I2C_DATA 0x40           // 0100 0000       写数据
#define OLED_I2C_BAUDRATE 400 * 1000 // 400k
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])


static uint32_t Oled_WriteByte(uint8_t regAddr, uint8_t byte)
{
    uint8_t buffer[] = {regAddr, byte};
    IoTI2cWrite(OLED_I2C_IDX, OLED_I2C_ADDR, buffer, sizeof(buffer));
    return IOT_SUCCESS;
}

uint32_t Oled_Init(void)
{
    static const uint8_t initCmds[] = {
        0xAE,
        0x00,
        0x10,
        0x40,
        0xB0,
        0x81,
        0xFF,
        0xA1,
        0xA6,
        0xA8,
        0x3F,
        0xC8,
        0xD3,
        0x00,
        0xD5,
        0x80,
        0xD8,
        0x05,
        0xD9,
        0xF1,
        0xDA,
        0x12,
        0xDB,
        0x30,
        0x8D,
        0x14,
        0xAF,
    };

    IoTGpioInit(IOT_IO_NAME_GPIO_13);
    IoTGpioInit(IOT_IO_NAME_GPIO_14);
    IoSetFunc(IOT_IO_NAME_GPIO_13, IOT_IO_FUNC_GPIO_13_I2C0_SDA);
    IoSetFunc(IOT_IO_NAME_GPIO_14, IOT_IO_FUNC_GPIO_14_I2C0_SCL);

    IoTI2cInit(OLED_I2C_IDX, OLED_I2C_BAUDRATE);

    for (int i = 0; i < ARRAY_SIZE(initCmds); i++)
    {
        uint32_t status = Oled_WriteByte(OLED_I2C_CMD, initCmds[i]);
        if (status != IOT_SUCCESS)
        {
            return status;
        }
    }
    return IOT_SUCCESS;
}

void Oled_Fill(uint8_t data)
{
    for (uint8_t m = 0; m < 8; m++)
    {
        Oled_WriteByte(OLED_I2C_CMD, 0xb0 + m); // 设置页地址（0~7）
        Oled_WriteByte(OLED_I2C_CMD, 0x00);     // 设置显示位置—列低地址
        Oled_WriteByte(OLED_I2C_CMD, 0x10);     // 设置显示位置—列高地址

        for (uint8_t n = 0; n < OLED_WIDTH; n++)
        {
            Oled_WriteByte(OLED_I2C_DATA, data);
        }
    }
    return IOT_SUCCESS;
}

void Oled_SetPos(uint8_t x, uint8_t y)
{
    Oled_WriteByte(OLED_I2C_CMD, 0xb0 + y);
    Oled_WriteByte(OLED_I2C_CMD, (x & 0xf0) >> 4 | 0x10);
    Oled_WriteByte(OLED_I2C_CMD, x & 0x0f);
}

void Oled_ShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font)
{
    uint8_t c = 0, i;

    c = ch - ' '; // 得到显示字符在库中的偏移地址
    if (x > OLED_WIDTH - 1)
    {
        x = 0;
        y += 2;
    }

    if (font == FONT8x16)
    {
        Oled_SetPos(x, y);
        for (i = 0; i < 8; i++)
        {
            Oled_WriteByte(OLED_I2C_DATA, Font8x16[c][i]);
        }

        Oled_SetPos(x, y + 1);
        for (i = 0; i < 8; i++)
        {
            Oled_WriteByte(OLED_I2C_DATA, Font8x16[c][i + 8]);
        }
    }
    else
    {
        Oled_SetPos(x, y);
        for (i = 0; i < 6; i++)
        {
            Oled_WriteByte(OLED_I2C_DATA, Font6x8[c][i]);
        }
    }
    return IOT_SUCCESS;
}

void Oled_ShowString(uint8_t x, uint8_t y, const char *str, Font font)
{
    uint8_t j = 0;
    if (str == NULL)
    {
        printf("param is NULL,Please check!!!\r\n");
        return;
    }

    while (str[j])
    {
        Oled_ShowChar(x, y, str[j], font);
        x += 8;
        if (x > 120)
        {
            x = 0;
            y += 2;
        }
        j++;
    }
    return IOT_SUCCESS;
}

void Oled_ShowChinese(uint8_t x, uint8_t y, uint8_t num, Font font)
{
    uint8_t i = 0;

    if (font == FONTCN12x12)
    {
        Oled_SetPos(x, y);
        for (i = 0; i < 12; i++)
        {
            Oled_WriteByte(OLED_I2C_DATA, FontCN12x12[2 * num][i]);
        }
        Oled_SetPos(x, y + 1);
        for (i = 0; i < 12; i++)
        {
            Oled_WriteByte(OLED_I2C_DATA, FontCN12x12[2 * num + 1][i]);
        }
    }
    if (font == FONTCN16x16)
    {
        Oled_SetPos(x, y);
        for (i = 0; i < 16; i++)
        {
            Oled_WriteByte(OLED_I2C_DATA, FontCN16x16[2 * num][i]);
        }
        Oled_SetPos(x, y + 1);
        for (i = 0; i < 16; i++)
        {
            Oled_WriteByte(OLED_I2C_DATA, FontCN16x16[2 * num + 1][i]);
        }
    }
    return IOT_SUCCESS;
}
